package com.study.cloud.registry.nacos.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingMaintainService;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.listener.Event;
import com.alibaba.nacos.api.naming.listener.EventListener;
import com.alibaba.nacos.api.naming.listener.NamingEvent;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.api.naming.pojo.Service;
import com.alibaba.nacos.api.naming.pojo.ServiceInfo;
import com.alibaba.nacos.common.executor.NameThreadFactory;
import com.alibaba.nacos.common.utils.CollectionUtils;
import com.google.common.collect.ImmutableMap;
import com.study.cloud.gateway.common.constants.BasicConst;
import com.study.cloud.gateway.common.constants.GatewayConst;
import com.study.cloud.gateway.common.rule.ServiceDefinition;
import com.study.cloud.gateway.common.rule.ServiceInstance;
import com.study.cloud.registry.api.RegisterCenterListener;
import com.study.cloud.registry.api.RegistryCenter;
import lombok.extern.slf4j.Slf4j;

import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author wangwancheng
 * @create 2025/7/19 17:16
 */
@Slf4j
public class NacosRegisterCenter implements RegistryCenter {
    /**
     * 注册地址
     */
    private String registerAddress;
    /**
     * 环境
     */
    private String env;
    /**
     * 主要维护服务实例信息
     */
    private NamingService namingService;
    /**
     * 主要维护服务定义信息
     */
    private NamingMaintainService namingMaintainService;
    /**
     * 监听器
     */
    private List<RegisterCenterListener> listeners = new CopyOnWriteArrayList<>();

    @Override
    public void init(String registryAddress, String env) {
        this.registerAddress = registryAddress;
        this.env = env;
        try {
            this.namingService = NacosFactory.createNamingService(registerAddress);
            this.namingMaintainService = NacosFactory.createMaintainService(registerAddress);
        } catch (NacosException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void register( ServiceDefinition serviceDefinition, ServiceInstance serviceInstance) {
        try {
            //构建nacos实例信息
            Instance nacosInstance = new Instance();
            nacosInstance.setInstanceId(serviceInstance.getServiceInstanceId());
            nacosInstance.setIp(serviceInstance.getIp());
            nacosInstance.setPort(serviceInstance.getPort());
            nacosInstance.setWeight(serviceInstance.getWeight());
            nacosInstance.setMetadata(ImmutableMap.of(GatewayConst.META_DATA_KEY, JSON.toJSONString(serviceInstance)));
            //注册服务实例
            namingService.registerInstance(serviceDefinition.getServiceId(),env, nacosInstance);
            //更新服务信息
            namingMaintainService.updateService(serviceDefinition.getServiceId(), env, 0, ImmutableMap.of(GatewayConst.META_DATA_KEY, JSON.toJSONString(serviceDefinition)));

            log.info("register service success :{} {}", serviceDefinition, serviceInstance);

        } catch (NacosException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void deRegister(ServiceDefinition serviceDefinition, ServiceInstance serviceInstance) {
        try {
            namingService.deregisterInstance(serviceDefinition.getServiceId(), env, serviceInstance.getIp(), serviceInstance.getPort());
            //namingMaintainService.deleteService(serviceDefinition.getServiceId(),env);
        } catch (NacosException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void subscribeAllServices(RegisterCenterListener listener) {
        listeners.add(listener);
        //订阅所有的服务
        doSubscribeAllServices();
        //定时任务 定时拉取
        Executors.newSingleThreadScheduledExecutor(new NameThreadFactory("NacosRegistryCenter-SubscribeAllServices-"))
                .scheduleWithFixedDelay(new Runnable() {
                    @Override
                    public void run() {
                        doSubscribeAllServices();
                    }
                }, 10, 10, TimeUnit.SECONDS);
    }

    private void doSubscribeAllServices() {
        try {
            //获取所有已经订阅的服务
            Set<String> serviceNames = namingService.getSubscribeServices().stream().map(ServiceInfo::getName).collect(Collectors.toSet());
            int pageNum = 1;
            int pageSize = 100;
            //nacos 的事件监听器
            EventListener listener = new NacosRegisterListener();
            //分页从nacos中获取服务列表
            List<String> serverList = namingService.getServicesOfServer(pageNum, pageSize, env).getData();
            while (CollectionUtils.isNotEmpty(serverList)) {
                log.info("subscribe all services from nacos, pageNum: {}, pageSize: {}, serviceNames: {}", pageNum, pageSize, serviceNames);
                for (String serviceName : serverList){
                    //如果包含 continue
                    if (serviceNames.contains(serviceName)) {
                       continue;
                    }
                    //订阅服务
                    log.info("subscribe service from nacos: {}", serviceName);
                    namingService.subscribe(serviceName,env, listener);
                }
                serverList = namingService.getServicesOfServer(pageNum++, pageSize, env).getData();
            }
        } catch (NacosException e) {
            throw new RuntimeException(e);
        }
    }

    public class NacosRegisterListener implements EventListener {
        @Override
        public void onEvent(Event event) {
            if (event instanceof NamingEvent){
                NamingEvent namingEvent = (NamingEvent) event;
                String serverName = namingEvent.getServiceName();
                try {
                    //获取服务定义信息
                    Service service = namingMaintainService.queryService(serverName,env);
                    ServiceDefinition serviceDefinition = JSON.parseObject(service.getMetadata().get(GatewayConst.META_DATA_KEY), ServiceDefinition.class);
                    //获取服务实例信息
                    List<Instance> instances = namingService.getAllInstances(serverName,env);
                    Set<ServiceInstance> serviceInstances = new HashSet<>();
                    for (Instance instance : instances) {
                        ServiceInstance serviceInstance = JSON.parseObject(instance.getMetadata().get(GatewayConst.META_DATA_KEY), ServiceInstance.class);
                        serviceInstances.add(serviceInstance);
                    }
                    listeners.forEach(listener->listener.onChange(serviceDefinition,serviceInstances));
                } catch (NacosException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
}
